<?php

namespace app\common;

use think\facade\App;
use Channel\Client;
use app\common\Worker;
use app\model\Channel;
use app\model\HttpChannel;
use Channel\Server;
use Exception;
use think\facade\Log;
use think\facade\Config;
use Workerman\Lib\Timer;

class MainWorkers extends Worker
{


    protected $config = [];

    public function __construct($daemon = false)
    {
        $this->setConfig('daemon', $daemon);
    }

    public function build()
    {
        $this->buildProgressChannelServer();
        $this->biuildWebAdminWorker();
        $this->buildHttpChannelServer();
        $this->buildPortChannelTplServer();
        $this->buildClientChannelServer();
    }

    public function setConfig($name, $value)
    {
        $this->config[$name] = $value;
    }

    //web管理面板
    public function biuildWebAdminWorker()
    {
        //web管理面板

        $port = config('channel.web_admin_port');
        $worker = new HttpServer('0.0.0.0', $port);


        if (empty($this->config['pidFile'])) {
            $this->config['pidFile'] = App::getRootPath() . 'runtime/worker.pid';
        }

        // 避免pid混乱
        $this->config['pidFile'] .= '_' . $port;

        // 设置应用根目录
        $worker->setRootPath(App::getRootPath());

        // 应用设置
        if (!empty($this->config['app_init'])) {
            $worker->appInit($this->config['app_init']);
            unset($this->config['app_init']);
        }


        $worker->setStaticOption('daemonize', $this->config['daemon']);

        // 开启HTTPS访问
        if (!empty($this->config['ssl'])) {
            $this->config['transport'] = 'ssl';
            unset($this->config['ssl']);
        }

        // 设置网站目录
        if (empty($this->config['root'])) {
            $this->config['root'] = App::getRootPath() . 'public';
        }

        $worker->setRoot($this->config['root']);
        unset($this->config['root']);



        // 全局静态属性设置
        foreach ($this->config as $name => $val) {
            if (in_array($name, ['stdoutFile', 'daemonize', 'pidFile', 'logFile'])) {
                $worker->setStaticOption($name, $val);
                unset($this->config[$name]);
            }
        }

        // 设置服务器参数
        $worker->option($this->config);
    }

    //进程间通信服务
    public function buildProgressChannelServer()
    {


        $channel_server = new ChannelServer('127.0.0.1', Config::get('channel.channel_server_port'));
    }


    //服务端Http监听服务
    public function buildHttpChannelServer()
    {
        $worker = new Worker('tcp://0.0.0.0:' . config('channel.channel_http_port'));
        $worker->name = 'HttpChannelServer';
        $worker->onWorkerStart = function ($worker) {
            Log::debug('HttpChannelServer start,listen to ' . $worker->getSocketName());

            Client::connect('127.0.0.1', Config::get('channel.channel_server_port'));

            Client::on('new_http_channel', function (HttpChannel $model_channel) {


                Log::debug('收到事件新域名监听:' . $model_channel->id . '(' . $model_channel->getAttr('domain') . ' ' . $model_channel->local_target_ip . ':' . $model_channel->local_target_port . ')');
            });
        };

        $worker->onMessage = function ($connection, $data) {
            dump($data);
        };
    }

    public function buildPortChannelTplServer()
    {
        $worker = new Worker();

        $worker->name = 'PortChannelTplServer';

        $worker->onWorkerStart = function (Worker $worker) {

            Log::debug('PortChannelTplServer start');
            Client::connect('127.0.0.1', Config::get('channel.channel_server_port'));

            Client::on('new_channel_worker', function (Channel $model_channel) use ($worker) {
                $progress_unique_key = uniqid();

                Log::debug('收到事件新端口隧道:' . $model_channel->id . '(' . $model_channel->getAttr('name') . ':' . $model_channel->server_port . ')' . ',worker uid :' . $progress_unique_key);
                $progress_name = '';

                $id = $worker->id++;

                $unid = uniqid();
                $pid = \pcntl_fork();
                // For master process.
                if ($pid > 0) {
                    static::$_progressWorkerPidMap[$pid] = $pid;
                    Log::debug('主进程记录子进程pid:'.$pid);
                    static::$_pidMap[$unid][$pid] = $pid;
                    static::$_idMap[$worker->workerId][$id]   = $pid;
                } // For child processes.
                elseif (0 === $pid) {
                    Log::debug('子进程运行'.posix_getpid());
                    \srand();
                    \mt_srand();
                    $worker->workerId = $unid;
                    $worker->reConstruct($model_channel->listen_address);
                    if ($worker->reusePort) {
                        $worker->listen();
                    }
                    if (static::$_status === static::STATUS_STARTING) {
                        static::resetStd();
                    }
                    static::$_pidMap  = array();
                    // Remove other listener.
                    foreach (static::$_workers as $key => $one_worker) {
                        if ($one_worker->workerId !== $worker->workerId) {
                            $one_worker->unlisten();
                            unset(static::$_workers[$key]);
                        }
                    }
                    Timer::delAll();
                    static::setProcessTitle('WorkerMan: worker process  ' . $worker->name . ' ' . $worker->getSocketName());
                    $worker->setUserAndGroup();
                    $worker->id = $id;
                    $worker->run();
                    $err = new Exception('event-loop exited');
                    static::log($err);
                    exit(250);
                } else {
                    throw new Exception("forkOneWorker fail");
                }
            });
        };


        
    }

    public function buildClientChannelServer()
    {

        $worker = new Worker('tcp://0.0.0.0:' . config('channel.client_service_port'));

        $worker->name = 'ClientChannelServer';

        $worker->onWorkerStart = function ($worker) {
            Log::debug('ClientSerivce start,listen to ' . $worker->getSocketName());
        };
    }
}
